using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using ProjectEuler.Core.Helpers;

namespace ProjectEuler.Core
{
    public class Problem50 : IProjectEulerProblem
    {
        private struct PrimeTerms
        {
            public int Sum;
            public int NumTerms;
        }

        protected int GetPrimeWithLargestConsecutiveSequenceLessThan(int max)
        {
            var primeTerms = new List<PrimeTerms>();
            var primes = GetAllPrimesBelow(max).ToArray();
            var size = primes.Count();

            // i will be the first term in the sequence
            for (int i = 0; i < size; i++)
            {
                var sum = 0;
                var terms = 0;
                // keep adding primes to the sequence, and record every sequence with a prime sum
                for (int j = i; j < size; j++)
                {
                    sum += primes[j];
                    terms++;
                    if ((sum < max) && (MathHelper.IsPrime(sum)))
                    {
                        primeTerms.Add(new PrimeTerms { NumTerms = terms, Sum = sum});
                    }
                    else if (sum >= max)
                    {
                        break;
                    }
                }
            }

            // the 'winner' is the sequence with the most terms
            var winner = primeTerms.OrderByDescending(p => p.NumTerms).First();
            return winner.Sum;
        }

        protected IEnumerable<int> GetAllPrimesBelow(int n)
        {
            yield return 2;
            int i = 3;
            while (i <= n)
            {
                if (MathHelper.IsPrime(i))
                {
                    yield return i;
                }
                i += 2;
            }
            yield break;
        }

        public int Number
        {
            get { return 50; }
        }

        public string Description
        {
            get { return "Which prime, below one-million, can be written as the sum of the most consecutive primes?"; }
        }

        public string Answer
        {
            get
            {
                return GetPrimeWithLargestConsecutiveSequenceLessThan(1000000).ToString();
            }
        }
    }

    [TestFixture]
    public class Problem50Tests : Problem50
    {
        [Test]
        public void Then_41_should_be_the_largest_prime_found_less_than_100()
        {
            Assert.AreEqual(41, GetPrimeWithLargestConsecutiveSequenceLessThan(100));
        }

        [Test]
        public void Then_953_should_be_the_largest_prime_found_less_than_1000()
        {
            Assert.AreEqual(953, GetPrimeWithLargestConsecutiveSequenceLessThan(1000));
        }
    }
}